
package com.hlkj.pay.app.merchant.ext.impl.hnapay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONObject;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.HnapayScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.constant.HnapayConstant;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.constant.HnapayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.dto.HnapayConfig;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.utils.HttpUtils;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.utils.RecepitUtil;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 主扫统一下单 用户扫支付码
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = HnapayExtConstant.JSAPI)
public class HnapayJSAPIOrderExtPt extends HnapaySceneCommonPayOrder implements HnapayScenePayOrderExtPt {

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
//        {"version", "tranCode", "merId", "merOrderId", "submitTime", "msgCiphertext"}
        //消息体加密的字段顺序
//        {"tranAmt","orgCode", "notifyServerUrl","merUserIp","expirTime","riskExpand","goodsInfo","orderSubject","orderDesc","payLimit","appId","openId","merchantId"}

        // 配置转换
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        HnapayConfig payConfig = getPayConfig(channelConfig, channelPayOrderContext.getMerchantAppChannelDO());
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        try {
            Map<String, String> param = new LinkedHashMap<>();
            param.put("version", "2.0");
            param.put("tranCode", "ITA10");
            param.put("merId", payConfig.getMerId());
            param.put("merOrderId", payOrderDO.getPayOrderNo());
            param.put("submitTime", DateUtils.dateToString(payOrderDO.getExpiredTime(), DatePattern.PURE_DATETIME_PATTERN));

            Map<String, String> msgCiphertext = new LinkedHashMap<>();
            msgCiphertext.put("tranAmt", payOrderDO.getAmount().toString());
            msgCiphertext.put("orgCode", "WECHATPAY");
            msgCiphertext.put("notifyServerUrl", "http://webtesttest2.hnapay.com/ita/notifyUrl.do");
            msgCiphertext.put("merUserIp", payOrderDO.getClientIp());
            msgCiphertext.put("expirTime", expireMinute(payOrderDO.getExpiredTime()).toString());
            msgCiphertext.put("riskExpand", "");
            msgCiphertext.put("goodsInfo", payOrderDO.getSubject());
            msgCiphertext.put("orderSubject", payOrderDO.getSubject());
            msgCiphertext.put("orderDesc", payOrderDO.getDescription());
            msgCiphertext.put("payLimit", "");
            msgCiphertext.put("appId", "wx5d2dd762e8a266d1");
            msgCiphertext.put("openId", "omCqSs3BUOVQlzLFd6OpjIVw3IyU");
            msgCiphertext.put("aliAppId", "");
            msgCiphertext.put("buyerLogonId", "");
            msgCiphertext.put("buyerId", "");
            msgCiphertext.put("merchantId", "2505211550004175696");//客户机构号
            msgCiphertext.put("holderName", "");
            msgCiphertext.put("identityType", "");
            msgCiphertext.put("identityCode", "");
            msgCiphertext.put("minAge", "");
            msgCiphertext.put("payType", "11");
            msgCiphertext.put("protocolId", "");

            param.put("signType", "3");
            param.put("remark", "1");
            param.put("merAttach", "1");
            param.put("charset", "1");
            param.put("msgCiphertext", RecepitUtil.encrpt(msgCiphertext, payConfig.getHnaM2PublicKey()));
            param.put("signValue", RecepitUtil.sign(payConfig.getMchM2PrivateKey(), param));

            String url = domain(channelPayOrderContext.isTest()) + HnapayConstant.TRADE_WECHAT_CREATE;
            log.info("新生支付下单req参数:{}", JsonUtils.toJsonString(param));
            String response = HttpUtils.postForm(url, param);
            log.info("新生支付下单返回参数:{}", response);

            JSONObject obj =  JsonUtils.parseObj(response);
            if ("0000".equals(obj.getStr("resultCode"))) {
                channelPayOrderContext.setPayDataType("data");
                channelPayOrderContext.setPayInfo(obj.getStr("payInfo"));
            } else {
                String respDesc = obj.getStr("errorMsg");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderContext.setRemark(respDesc);
                } else {
                    channelPayOrderContext.setRemark("新生支付下单查询返回错误信息为空,错误码为:" + obj.getStr("resultCode"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("新生支付下单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderContext.setRemark("新生支付下单请求失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayType(PayWayDO payWayDO) {
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(payType)) return "";
        switch (payType) {
            case WECHAT:
                return "WXPAY";
            case ALIPAY:
                return "ALIPAY";
        }
        return "";
    }

    private String getPaySubType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(scenePayType) || Objects.isNull(payType)) return "";
        switch (scenePayType) {
            case APP:
            case H5:
                return "H5";
            case MINI_APP:
                return "MINI_PROGRAM";
            case JSAPI:
                return "JSAPI";
            case QR:
                switch (payType) {
                    case WECHAT:
                        return "JSAPI";
                    case ALIPAY:
                        return "NATIVE";
                }
        }
        return "";
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }

}
